﻿using System;
using System.Data;
using Npgsql;
using PureMVC.Interfaces;
using PureMVC.Patterns;

namespace SMS.Core.Model
{
    public class PersistentConnectionProxy : Proxy, IProxy
    {
        #region Constants

        public new const string NAME = "NpgsqlConnectionProxy";

        #endregion

        #region Members

        private NpgsqlConnection conn;

        #endregion

        #region Constructors

        public PersistentConnectionProxy()
        {
            conn = new NpgsqlConnection();
        }

        public PersistentConnectionProxy(string connString)
            : base(NAME)
        { 
            InitializeProxy(connString);
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Opens the connection to the database with the settings
        /// <c>NpgsqlConnection</c> this proxy handles.
        /// </summary>
        /// <returns>Returns true if a connection is open</returns>
        public bool OpenConnection()
        {
            try
            { 
                conn.Open(); 
            }
            catch (NpgsqlException e)
            {
                SendNotification(ModelConstants.Connection.CONNECT_FAILED, e.BaseMessage);
            }
            if (conn.State == ConnectionState.Open)
            {
                SendNotification(ModelConstants.Connection.CONNECTED, Data);

                // TESTING TESTING LANG PO! haha, mugana na ang SyncNotifications! xD
                // -------------------------------------------------------------------
                //NpgsqlCommand command = new NpgsqlCommand("LISTEN sms", conn);
                //conn.Notification +=new NotificationEventHandler(conn_Notification);
                //command.ExecuteNonQuery();
                // -------------------------------------------------------------------

                return true;
            }
            return false;
        }
        
        /// <summary>
        /// Closes the connection to the PostgreSQL database.
        /// </summary>
        /// <returns>True if the connection was closed successfully.</returns>
        public bool CloseConnection()
        {
            conn.Close();
            if (conn.State == ConnectionState.Closed)
            {
                SendNotification(ModelConstants.Connection.DISCONNECTED, Data);
                return true;
            }
            return false;
        }

        #endregion

        #region Properties

        public new NpgsqlConnection Data
        {
            get { return conn; }
            set { conn = value; }
        }

        public NpgsqlConnection getConn()
        {
            return Data;
        }

        public ConnectionState ConnectionState
        {
            get { return conn.State; }
        }

        #endregion

        #region Private & Internal Methods

        private void InitializeProxy(string connString)
        {
            conn = new NpgsqlConnection(connString);
            conn.StateChange += new StateChangeEventHandler(conn_StateChange);
        }

        #region Event Handlers
        /// <summary>
        /// Han
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void conn_StateChange(object sender, StateChangeEventArgs e)
        {
            switch (e.CurrentState)
            {
                case ConnectionState.Open:
                    SendNotification(ModelConstants.Connection.CONNECTED, Data);
                    break;
                case ConnectionState.Closed:
                    SendNotification(ModelConstants.Connection.DISCONNECTED, Data);
                    break;
                case ConnectionState.Broken:
                    SendNotification(ModelConstants.Connection.BROKEN, Data);
                    break;
                case ConnectionState.Connecting:
                    SendNotification(ModelConstants.Connection.CONNECTING, Data);
                    break;
                case ConnectionState.Executing:
                    SendNotification(ModelConstants.Connection.EXECUTING, Data);
                    break;
            }
        }

        /// <summary>
        /// Handles notifications from the PostgreSQL backend.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void conn_Notification(object sender, NpgsqlNotificationEventArgs e)
        {
            SendNotification(ModelConstants.Domain.UPDATED_TABLE, e);
        }

        #endregion

        #endregion
    }
}